{$MODE objfpc}

//
// String object interface
//

unit PythonStringObject;

// Type PyStringObject represents a character string.  An extra zero byte is
// reserved at the end to ensure it is zero-terminated, but a size is
// present so strings with null bytes in them can be represented.  This
// is an immutable object type.
// 
// There are functions to create new string objects, to test
// an object for string-ness, and to get the
// string value.  The latter function returns a null pointer
// if the object is not of the proper type.
// There is a variant that takes an explicit size as well as a
// variant that assumes a zero-terminated string.  Note that none of the
// functions should be applied to nil objects.

// Caching the hash (ob_shash) saves recalculation of a string's hash value.
//   Interning strings (ob_sstate) tries to ensure that only one string
//   object with a given value exists, so equality tests can be one pointer
//   comparison.  This is generally restricted to strings that "look like"
//   Python identifiers, although the intern() builtin can be used to force
//   interning of any string.
//   Together, these sped the interpreter by up to 20%.

interface
  uses PythonTypes;

type
  PyStringObject = record
      //PyObject_VAR_HEAD
    	ob_refcnt: 	Py_ssize_t;
    	ob_type: 	  PyTypeObjectPtr;
      ob_size:    Py_ssize_t;

      ob_shash:   Long;
      ob_sstate:  Integer;
      ob_sval:    PChar;

       // Invariants:
       // *     ob_sval contains space for 'ob_size+1' elements.
       // *     ob_sval[ob_size] == 0.
       // *     ob_shash is the hash of the string or -1 if not computed yet.
       // *     ob_sstate != 0 iff the string object is in stringobject.c's
       // *       'interned' dictionary; in this case the two references
       // *       from 'interned' to this object are *not counted* in ob_refcnt.
    end;
     
const
  SSTATE_NOT_INTERNED = 0; {$EXTERNALSYM SSTATE_NOT_INTERNED}
  SSTATE_INTERNED_MORTAL = 1; {$EXTERNALSYM SSTATE_INTERNED_MORTAL}
  SSTATE_INTERNED_IMMORTAL = 2; {$EXTERNALSYM SSTATE_INTERNED_IMMORTAL}

var
  PyBaseString_Type: PyTypeObject; cvar; external;
  PyString_Type: PyTypeObject; cvar; external;

function PyString_FromStringAndSize(s: PChar; sz: Py_ssize_t): PyObjectPtr; cdecl; external;
function PyString_FromString(s: PChar): PyObjectPtr; cdecl; external;
//function PyString_FromFormatV(s: PChar, va_list): PyObjectPtr; cdecl; external;
function PyString_FromFormat(s: PChar; args: Array of Const): PyObjectPtr; cdecl; external;
function PyString_Size(ob: PyObjectPtr): Py_ssize_t; cdecl; external;
function PyString_AsString(ob: PyObjectPtr): PChar; cdecl; external;
function PyString_Repr(ob: PyObjectPtr; int: Integer): PyObjectPtr; cdecl; external;
procedure PyString_Concat(ob: PyObjectPtrPtr; ob2: PyObjectPtr ); cdecl; external;
procedure PyString_ConcatAndDel(ob: PyObjectPtrPtr; ob2: PyObjectPtr); cdecl; external;
function _PyString_Resize(ob: PyObjectPtrPtr; sz: Py_ssize_t): Integer; cdecl; external;
function _PyString_Eq(o1, o2: PyObjectPtr): Integer; cdecl; external;
function PyString_Format(o1, o2: PyObjectPtr): PyObjectPtr; cdecl; external;
function _PyString_FormatLong(ob: PyObjectPtr; i1, i2, i3: Integer; buf: PPChar; int: IntPtr): PyObjectPtr; cdecl; external;
function PyString_DecodeEscape(s: PChar; sz: Py_ssize_t; s1: PChar; sz2: Py_ssize_t; s3: PChar): PyObjectPtr; cdecl; external;

procedure PyString_InternInPlace(o: PyObjectPtrPtr); cdecl; external;
procedure PyString_InternImmortal(o: PyObjectPtrPtr); cdecl; external;
function PyString_InternFromString(s: PChar): PyObjectPtr; cdecl; external;
procedure _Py_ReleaseInternedStrings(); cdecl; external;

// _PyString_Join(sep, x) is like sep.join(x).  sep must be PyStringObject*,
//   x must be an iterable object. */
function _PyString_Join(sep, x: PyObjectPtr): PyObjectPtr; cdecl; external;

// --- Generic Codecs ----------------------------------------------------- */

 // Create an object by decoding the encoded string s of the
 //   given size.

function  PyString_Decode(
    str: PChar;              // encoded string */
    size: Py_ssize_t;            // size of buffer */
    encoding: PChar;       // encoding */
    errors: PChar          // error handling */
    ): PyObjectPtr; cdecl; external;

// Encodes a char buffer of the given size and returns a 
//   Python object. */

function PyString_Encode(
    s:    PChar;            // string char buffer */
    size: Py_ssize_t;       // number of chars to encode */
    encoding: PChar;        // encoding */
    errors: PChar          // error handling */
    ): PyObjectPtr; cdecl; external;

// Encodes a string object and returns the result as Python 
//   object. */

function PyString_AsEncodedObject(
    str:      PyObjectPtr;	 	// string object */
    encoding: PChar;	        // encoding */
    errors:   PChar 		      // error handling */
    ): PyObjectPtr; cdecl; external;

// Encodes a string object and returns the result as Python string
//   object.   
// 
// If the codec returns an Unicode object, the object is converted
// back to a string using the default encoding.
// 
// DEPRECATED - use PyString_AsEncodedObject() instead. */

function PyString_AsEncodedString(
    str:      PyObjectPtr;	 	// string object */
    encoding: PChar;	  // encoding */
    errors:   PChar		// error handling */
    ): PyObjectPtr; cdecl; external;

// Decodes a string object and returns the result as Python 
//   object. */

function PyString_AsDecodedObject(
     str:     PyObjectPtr;	 	// string object */
    encoding: PChar;	// encoding */
    errors:   PChar		// error handling */
    ): PyObjectPtr; cdecl; external;

// Decodes a string object and returns the result as Python string
   // object.  
   // 
   // If the codec returns an Unicode object, the object is converted
   // back to a string using the default encoding.
   // 
   // DEPRECATED - use PyString_AsDecodedObject() instead. */

function PyString_AsDecodedString(
    str:      PyObjectPtr;	 	// string object */
    encoding: PChar;	        // encoding */
    errors:   PChar		      // error handling */
    ): PyObjectPtr; cdecl; external;

// Provides access to the internal data buffer and size of a string
   // object or the default encoded version of an Unicode object. Passing
   // NULL as *len parameter will force the string buffer to be
   // 0-terminated (passing a string with embedded NULL characters will
   // cause an exception).  */

function PyString_AsStringAndSize(
    obj: PyObjectPtr;	    // string or Unicode object */
    s: PPChar;		        // pointer to buffer variable */
    len: Pointer	        // pointer to length variable or NULL (only possible for 0-terminated strings) */
    ): Integer; register; external;

    // Use only if you know it's a string
    //#define PyString_CHECK_INTERNED(op) (((PyStringObject *)(op))->ob_sstate)

    // Macro, trading safety for speed
    //#define PyString_AS_STRING(op) (((PyStringObject *)(op))->ob_sval)
    //#define PyString_GET_SIZE(op)  (((PyStringObject *)(op))->ob_size)
    
    function PyString_Check(op: PyObjectPtr) : Boolean;
    function PyString_CheckExact(op: PyObjectPtr) : Boolean;
    
implementation
  uses PythonObject;
  
function PyString_Check(op: PyObjectPtr) : Boolean; 
begin
  result := PyObject_TypeCheck(op, @PyString_Type);
end;

function PyString_CheckExact(op: PyObjectPtr) : Boolean;
begin
  result := op^.ob_type = @PyString_Type;
end;


end.